using UnityEngine;
using System.Collections;
using Unity.VisualScripting;

public class Entity : MonoBehaviour
{
    enum Direction { Left = -1, Right = 1 }

    // ========================================================================

    [Header("Entity")]
    [SerializeField] EntityState initState;
    [SerializeField] Direction facingDirection;
    [SerializeField] protected Transform groundCheckPoint;
    [SerializeField] protected float groundCheckDistance;
    [SerializeField] protected Transform wallCheckPoint;
    [SerializeField] protected float wallCheckDistance;
    [SerializeField] protected LayerMask groundLayer;

    protected StateMachine stateMachine;
    protected Animator animator;
    protected EntityVFX vfx;
    public Rigidbody2D rb { get; private set; }

    [Header("KnockBack")]
    bool isKnocked = false;
    [SerializeField] float knockBackDuration;
    [SerializeField] Vector2 knockBackDirection;

    // ========================================================================

    protected virtual void Awake()
    {
        stateMachine = new StateMachine();
        animator = GetComponentInChildren<Animator>();
        vfx = GetComponent<EntityVFX>();
        rb = GetComponent<Rigidbody2D>();
    }

    protected virtual void Start() => stateMachine.Init(initState);

    protected virtual void Update()
    {
        stateMachine.Process();
        stateMachine.LateProcess();
    }

    protected virtual void OnDrawGizmos()
    {
        Gizmos.DrawLine(groundCheckPoint.position, groundCheckPoint.position + new Vector3(0, -groundCheckDistance));
        Gizmos.DrawLine(wallCheckPoint.position, wallCheckPoint.position + new Vector3(wallCheckDistance * FacingDirection(), 0));
    }

    // ========================================================================

    public bool IsGroundDetected() => Physics2D.Raycast(groundCheckPoint.position, Vector2.down, groundCheckDistance, groundLayer);
    public bool IsWallDetected() => Physics2D.Raycast(wallCheckPoint.position, Vector2.right * FacingDirection(), wallCheckDistance, groundLayer);
    public int FacingDirection() => (int)direction;
    public float GetVelocity(int index) => rb.velocity[index];

    public void ResetVelocity()
    {
        if (!isKnocked) rb.velocity = Vector2.zero;
    }

    public void SetVelocity(float x, float y)
    {
        if (isKnocked) return;

        rb.velocity = new Vector2(x, y);

        if (x > 0 && direction == Direction.Left)
        {
            direction = Direction.Right;
            transform.Rotate(0, 180, 0);
        }
        else if (x < 0 && direction == Direction.Right)
        {
            direction = Direction.Left;
            transform.Rotate(0, 180, 0);
        }
    }

    public void Flip()
    {
        transform.Rotate(0, 180, 0);
        direction = (Direction)(-(int)direction);
    }

    public virtual void Damage()
    {
        vfx.StartCoroutine(vfx.OnDamageVFX());
        StartCoroutine(KnockBack(knockBackDirection, knockBackDuration));
    }

    private IEnumerator KnockBack(Vector2 knockback, float duration)
    {
        isKnocked = true;
        rb.velocity = knockback;
        yield return new WaitForSeconds(duration);
        rb.velocity = Vector2.zero;
        isKnocked = false;
    }
}
